package com.gitee.elf.core.data

import com.google.gson.*
import taboolib.common.io.runningClasses

object Serializer {

    val gson = GsonBuilder()
        .setPrettyPrinting()
        .excludeFieldsWithoutExposeAnnotation().run {
            runningClasses.forEach {
                if (it.isAnnotationPresent(SerializerType::class.java)) {
                    registerTypeHierarchyAdapter(
                        it.getAnnotation(SerializerType::class.java).bind.java,
                        it.newInstance()
                    )
                }
            }
            create()
        }!!

    fun JsonPrimitive.toActualJson(): String {
        val string = this.asString
        return string.substring(0, string.length - 1)
    }

    fun JsonElement.asData(): Data {

        return if (this is JsonPrimitive) {
            val string = asString
            return when (string[string.lastIndex]) {
                'd' -> DataDouble(toActualJson().toDouble())
                'i' -> DataInt(toActualJson().toInt())
                'b' -> DataBoolean(toActualJson().toBoolean())
                's' -> DataString(toActualJson())
                else -> DataString(toActualJson())
            }
        } else if (this is JsonObject) {
            DataObject().let { data ->
                this.entrySet().forEach { data[it.key] = it.value.asData() }
                data
            }
        } else if (this is JsonArray) {
            DataList().let { data ->
                this.forEach { data += it.asData() }
                data
            }
        } else {
            DataString(this.toString())
        }
    }

    fun toJsonTree(value: Any): JsonElement {
        return gson.toJsonTree(value)
    }

    fun toJson(value: Any): String {

        return gson.toJson(value)
    }

    fun fromJson(value: String, clazz: Class<*>): Any {
        return gson.fromJson(value, clazz)
    }

    fun fromJson(value: JsonElement, clazz: Class<*>): Any {
        return gson.fromJson(value, clazz)
    }

    inline fun <reified T> fromJson(json: JsonElement): T {
        return gson.fromJson(json, T::class.java)
    }

    inline fun <reified T> fromJson(json: String): T {
        return gson.fromJson(json, T::class.java)
    }

}